<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>3.分形图案</title>
    <style>
        canvas{
            border:1px solid #aaa;
            margin: 0 auto;
            display: block;
        }
    </style>
</head>
<body>
    <canvas width="800" height="800"></canvas>

    <script src="/common/lib/gl-renderer.js"></script>

    <script type="module">
        /**
         * gl-renderer 在 WebGL 底层的基础上进行了一些简单的封装，以便于我们将重点放在提供几何数据、设置变量和编写 Shader 上，不用因为创建 buffer 等细节而分心
         * 第一步: 创建 Renderer 对象
         * 第二步: 创建并启用 WebGL 程序
         * 第三步: 设置 uniform 变量
         * 第四步: 将顶点数据送入缓冲区
         * 第五步: 渲染
        */

        //第一步:
        const canvas = document.querySelector('canvas');
        const renderer = new GlRenderer(canvas);

        
        const vertex = ` 
            attribute vec2 a_vertexPosition;
            attribute vec2 uv;
            varying vec2 vUv;
            
            void main() {
                gl_PointSize = 1.0;
                vUv = uv;
                gl_Position = vec4(a_vertexPosition, 1, 1);
            }
        `;
        /**
         * 解析：
         * fract(vUv * rows)：fract函数取一个数的小数部分，vUv从0-1变化，乘以rows（网格的行列数）之后，得到rows周期的变化的数值，也就是分成了rows份
         * step(st.x, 0.9)：step阶梯函数，第一个参数大于第二个参数时返回0，否则1，这样实现片元着色器的阶梯式的颜色插值
         * mix(vec3(0.8), vec3(1.0), d1 * d2)：实现线性插值，当st.x<0.9并且st.y>0.1时，返回vec3(1.0)白色，否则vec3(0.8)灰色
         */ 
        // const fragment = ` 
        //     #ifdef GL_ES
        //     precision highp float;
        //     #endif

        //     varying vec2 vUv;

        //     float random (vec2 st) {
        //         return fract(sin(dot(st.xy,
        //                             vec2(12.9898,78.233)))*
        //             43758.5453123);
        //     }

        //     void main() {
        //         gl_FragColor.rgb = vec3(random(vUv));
        //         gl_FragColor.a = 1.0;
        //     }
        // `;


        // const fragment = ` 
        //     #ifdef GL_ES
        //     precision highp float;
        //     #endif

        //     varying vec2 vUv;
        //     float random (vec2 st) {
        //         return fract(sin(dot(st.xy,
        //                             vec2(12.9898,78.233)))*
        //             43758.5453123);
        //     }

        //     void main() {
        //         vec2 st = vUv * 10.0;
        //         gl_FragColor.rgb = vec3(random(floor(st)));
        //         gl_FragColor.a = 1.0;
        //     }
        // `;


        // const fragment = ` 
        //     #ifdef GL_ES
        //     precision highp float;
        //     #endif

        //     varying vec2 vUv;

        //     uniform float uTime;

        //     float random (vec2 st) {
        //         return fract(sin(dot(st.xy,
        //                             vec2(12.9898,78.233)))*
        //             43758.5453123);
        //     }

        //     void main() {
        //         vec2 st = vUv * vec2(100.0, 50.0);

        //         st.x -= (1.0 + 10.0 * random(vec2(floor(st.y)))) * uTime;

        //         vec2 ipos = floor(st);  // integer
        //         vec2 fpos = fract(st);  // fraction

        //         vec3 color = vec3(step(random(ipos), 0.7));
        //         color *= step(0.2,fpos.y);

        //         gl_FragColor.rgb = color;
        //         gl_FragColor.a = 1.0;
        //     }
        // `;

        const fragment = ` 
            #ifdef GL_ES
            precision mediump float;
            #endif

            #define PI 3.14159265358979323846

            varying vec2 vUv;
            uniform vec2 u_resolution;
            uniform int rows;

            float random (in vec2 _st) {
                return fract(sin(dot(_st.xy,
                                    vec2(12.9898,78.233)))*
                    43758.5453123);
            }

            vec2 truchetPattern(in vec2 _st, in float _index){
                _index = fract(((_index-0.5)*2.0));
                if (_index > 0.75) {
                    _st = vec2(1.0) - _st;
                } else if (_index > 0.5) {
                    _st = vec2(1.0-_st.x,_st.y);
                } else if (_index > 0.25) {
                    _st = 1.0-vec2(1.0-_st.x,_st.y);
                }
                return _st;
            }

            void main() {
                vec2 st = vUv * float(rows);
                vec2 ipos = floor(st);  // integer
                vec2 fpos = fract(st);  // fraction

                vec2 tile = truchetPattern(fpos, random( ipos ));
                float color = 0.0;

                color = smoothstep(tile.x-0.3,tile.x,tile.y)-
                        smoothstep(tile.x,tile.x+0.3,tile.y);

                gl_FragColor = vec4(vec3(color),1.0);
            }
        `;
        
        const program = renderer.compileSync(fragment, vertex);

        renderer.useProgram(program);
        // renderer.uniforms.center = [0, 0];
        // renderer.uniforms.scale = 1;
        // renderer.uniforms.iterations = 256;

        renderer.uniforms.rows = 20;

        renderer.setMeshData([{
            positions: [
                [-1, -1],
                [-1, 1],
                [1, 1],
                [1, -1],
            ],
            attributes: {
                uv: [
                    [0, 0],
                    [0, 1],
                    [1, 1],
                    [1, 0],
                ],
            },
            cells: [[0, 1, 2], [2, 0, 3]],
        }]);

        renderer.render();

    </script>
</body>
</html>